﻿/**
 * @file sdk_framework.hpp
 * @date 2021/07/16 14:07
 * 
 * @author harrybao (harrybao@123u.com)
 * 
 * @brief SDKFramework内部实现
 * 
 * @version v1.0.0
 * 
 * @copyright Copyright © 2021 All Rights Reserved 上海欢乐互娱网络科技有限公司
 * 
 * @par history:
 * <table>
 * <tr><th>Date                     <th>Version     <th>Author      <th>Description
 * <tr><td>2021/07/16 14:07         <td>1.0.0       <td>harrybao    <td>创建初始版本
 * </table>
 */

#pragma once

#ifdef _WIN32
#include <WinSock2.h>
#include <Windows.h>
#include <libloaderapi.h>
#include <errhandlingapi.h>
#else
#include <dlfcn.h>
#endif // _WIN32


#include "link_util/platform_link.h"
#include "link_util_api.h"


/**
 * @brief SDK框架
 * 
 */
class SDKFramework {
public:
  SDKFramework()
      : shared_lib_handle_(0),
        err_(0),
        create_platform_link_func_(nullptr),
        destroy_platform_link_func_(nullptr) {}

  ~SDKFramework() { Uninit(); }
  SDKFramework(const SDKFramework&) = delete;
  SDKFramework(SDKFramework&&) = delete;
  SDKFramework& operator=(const SDKFramework&) = delete;
  SDKFramework& operator=(SDKFramework&&) = delete;
public:
#ifdef _WIN32
  using module_handle_type = HMODULE;
  using error_type = DWORD;
#else
  using module_handle_type = void*;
  using error_type = const char*;
#endif // _WIN32
  /// PlatformLink类型别名
  using platform_link_type = link_util::PlatformLink;

  /**
   * @brief 初始化
   * 
   * @param shared_lib_path
   * @return true 
   * @return false 
   */
  bool Init(const std::string &shared_lib_path) {
    if (!Uninit()) {
      return false;
    }

    if (shared_lib_path.empty()) {
      return false;
    }

#ifdef _WIN32
    shared_lib_handle_ = ::LoadLibraryA(shared_lib_path.c_str());
    err_ = ::GetLastError();
    if (err_) {
      std::cerr << "LoadLibrary error: " << err_ << '\n';
      return false;
    }
#else
    shared_lib_handle_ = dlopen(shared_lib_path.c_str(), RTLD_NOW);
    err_ = dlerror();
    if (err_) {
    //   std::cerr << "LoadLibrary error: " << err_ << '\n';
      return false;
    }
#endif  // _WIN32

#ifdef _WIN32
    create_platform_link_func_ =
        (link_util::create_platform_link_func_type)::GetProcAddress(
            shared_lib_handle_, link_util::CREATE_PLATFORM_LINK_FUNC_NAME);
    err_ = ::GetLastError();
    if (err_) {
      std::cerr << "Load create_platform_link_func error: " << err_ << '\n';
      return false;
    }

    destroy_platform_link_func_ =
        (link_util::destroy_platform_link_func_type)::GetProcAddress(
            shared_lib_handle_, link_util::DESTROY_PLATFORM_LINK_FUNC_NAME);
    err_ = ::GetLastError();
    if (err_) {
      std::cerr << "Load destroy_platform_link_func error: " << err_ << '\n';
      return false;
    }
#else
    create_platform_link_func_ =
        (link_util::create_platform_link_func_type)dlsym(
            shared_lib_handle_, link_util::CREATE_PLATFORM_LINK_FUNC_NAME);

    err_ = dlerror();
    if (err_) {
      // std::cerr << "load create_platform_link_func error: " << err_ << '\n';
      return false;
    }

    destroy_platform_link_func_ =
        (link_util::destroy_platform_link_func_type)dlsym(
            shared_lib_handle_, link_util::DESTROY_PLATFORM_LINK_FUNC_NAME);

    err_ = dlerror();
    if (err_) {
      // std::cerr << "load destroy_platform_link_func error: " << err_ << '\n';
      return false;
    }

#endif  // _WIN32

    return true;
  }

  /**
   * @brief 不初始化
   * 
   * @return true 
   * @return false 
   */
  bool Uninit() {
    if (!shared_lib_handle_) {
      return true;
    }
    // std::cout << "FreeLibrary..." << '\n';
#ifdef _WIN32
    if (::FreeLibrary(shared_lib_handle_)) {
      std::cout << "FreeLibrary success" << '\n';
      shared_lib_handle_ = nullptr;
      create_platform_link_func_ = nullptr;
      destroy_platform_link_func_ = nullptr;
    } else {
      err_ = ::GetLastError();
      if (err_) {
        std::cerr << "FreeLibrary error: " << err_ << '\n';
      }
      return false;
    }
#else
    if (0 == dlclose(shared_lib_handle_)) {
      // std::cout << "FreeLibrary success" << '\n';
      shared_lib_handle_ = nullptr;
      create_platform_link_func_ = nullptr;
      destroy_platform_link_func_ = nullptr;
    } else {
      err_ = dlerror();
      if (err_) {
        // std::cerr << "FreeLibrary error: " << err_ << '\n';
      }
      return false;
    }

#endif  // _WIN32

    return true;
  }

  /**
   * @brief 创建PlatformLink
   * 
   * @return link_util::PlatformLink* PlatformLink指针
   */
  platform_link_type* CreatePlatformLink() const {
    if (!create_platform_link_func_) {
      return nullptr;
    }
    return create_platform_link_func_();
  }
  
  /**
   * @brief 销毁PlatformLink
   * 
   * @param platform_link_ptr PlatformLink指针
   */
  void DestroyPlatformLink(platform_link_type* platform_link_ptr) const {
    if (!platform_link_ptr) {
      return;
    }
    if (!destroy_platform_link_func_) {
      return;
    }
    destroy_platform_link_func_(platform_link_ptr);
  }

  /**
   * @brief 获取最后一个错误码
   * 
   * @return error_type 错误码类型
   */
  error_type GetLastError() const { return err_; }

 private:
  module_handle_type shared_lib_handle_;                                    ///< 动态库句柄
  error_type err_;                                                          ///< 错误码
  link_util::create_platform_link_func_type create_platform_link_func_;     ///< 创建PlatformLink的函数指针
  link_util::destroy_platform_link_func_type destroy_platform_link_func_;   ///< 销毁PlatformLink的函数指针
};